package org.ourgrid.acceptance.util.broker;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.easymock.classextension.EasyMock;
import org.ourgrid.acceptance.util.BrokerAcceptanceUtil;
import org.ourgrid.broker.BrokerServerModule;
import org.ourgrid.common.interfaces.LocalWorkerProvider;
import org.ourgrid.common.interfaces.control.BrokerControl;
import org.ourgrid.common.interfaces.control.BrokerControlClient;
import org.ourgrid.common.interfaces.to.RequestSpec;
import org.ourgrid.common.spec.OurGridSpecConstants;
import org.ourgrid.common.spec.peer.PeerSpec;
import org.ourgrid.matchers.ControlOperationResultMatcher;
import org.ourgrid.peer.PeerConstants;

import br.edu.ufcg.lsd.commune.container.ObjectDeployment;
import br.edu.ufcg.lsd.commune.container.control.ModuleNotStartedException;
import br.edu.ufcg.lsd.commune.container.logging.CommuneLogger;
import br.edu.ufcg.lsd.commune.context.ModuleContext;
import br.edu.ufcg.lsd.commune.identification.ContainerID;
import br.edu.ufcg.lsd.commune.identification.DeploymentID;
import br.edu.ufcg.lsd.commune.identification.ServiceID;
import br.edu.ufcg.lsd.commune.testinfra.AcceptanceTestUtil;

public class Req_309_Util extends BrokerAcceptanceUtil {

	private BrokerAcceptanceUtil brokerAcceptanceUtil = new BrokerAcceptanceUtil(context);
	
	public Req_309_Util(ModuleContext context) {
		super(context);
	}
	
	public PeerSpec setPeers(String userName, String serverName, String publicKey, BrokerServerModule component, 
			List<TestJob> testJobs, List<LocalWorkerProvider> oldPeers) {
		PeerSpec peerSpec = createPeerSpec(userName, serverName);
		setPeers(true, peerSpec, publicKey, component, testJobs, oldPeers);
		return peerSpec;
	}
	
	public PeerSpec setPeers(String userName, String serverName, String publicKey, BrokerServerModule component) {
		PeerSpec peerSpec = createPeerSpec(userName, serverName);
		setPeers(true, peerSpec, publicKey, component);
		return peerSpec;
	}
	
	public PeerSpec setPeers(boolean isBrokerStarted, String userName, String serverName, String publicKey, BrokerServerModule component) {
		PeerSpec peerSpec = createPeerSpec(userName, serverName);
		setPeers(isBrokerStarted, peerSpec, publicKey, component);
		return peerSpec;
	}

	public void setPeers(boolean isBrokerStarted, String publicKey, BrokerServerModule component) {
		PeerSpec peerSpec = new PeerSpec();
		setPeers(false, peerSpec, publicKey, component);
	}
	
	public void setPeers(boolean isBrokerStarted, BrokerServerModule component) {
		CommuneLogger newLogger = component.getLogger();
		
		if (newLogger == null) {
			newLogger = EasyMock.createMock(CommuneLogger.class);
		}
		
		EasyMock.reset(newLogger);
		
		component.setLogger(newLogger);
		
		newLogger.info("Trying to set peers.");
		
		BrokerControl brokerControl = brokerAcceptanceUtil.getBrokerControl(component);
		ObjectDeployment brokerOD = brokerAcceptanceUtil.getBrokerControlDeployment(component);
		
		BrokerControlClient brokerControlClientMock = EasyMock.createMock(BrokerControlClient.class);
		
		List<PeerSpec> peers = new ArrayList<PeerSpec>();
		if (isBrokerStarted) {
			newLogger.info("Operation succeed.");
			brokerControlClientMock.operationSucceed(ControlOperationResultMatcher.noError());
		} else {
			brokerControlClientMock.operationSucceed(
					ControlOperationResultMatcher.eqCauseType("Broker control was not started", ModuleNotStartedException.class));
			newLogger.error("Broker control was not started.");
			
		}
		

		EasyMock.replay(newLogger);
		EasyMock.replay(brokerControlClientMock);

		AcceptanceTestUtil.setExecutionContext(component, brokerOD, brokerOD.getDeploymentID().getPublicKey());
		brokerControl.setPeers(brokerControlClientMock, peers);
		
		EasyMock.verify(brokerControlClientMock);
		EasyMock.verify(newLogger);
		
	}
	
	public void setPeers(boolean isBrokerStarted, PeerSpec peerSpec, String peerPublicKey, BrokerServerModule component) {
		setPeers(isBrokerStarted, peerSpec, peerPublicKey, component, null, null);
	}
	
	public void setPeers(boolean isBrokerStarted, PeerSpec peerSpec, String peerPublicKey, BrokerServerModule component, 
			List<TestJob> testJobs, List<LocalWorkerProvider> oldPeers) {
		CommuneLogger oldLogger = component.getLogger();
		CommuneLogger newLogger = EasyMock.createMock(CommuneLogger.class);
		
		component.setLogger(newLogger);
		
		newLogger.info("Trying to set peers.");
		
		BrokerControl brokerControl = brokerAcceptanceUtil.getBrokerControl(component);
		ObjectDeployment brokerOD = brokerAcceptanceUtil.getBrokerControlDeployment(component);
		
		BrokerControlClient brokerControlClientMock = EasyMock.createMock(BrokerControlClient.class);
		DeploymentID clientID = new DeploymentID("bcc1@b/c","d");
		AcceptanceTestUtil.publishTestObject(application, clientID, brokerControlClientMock, BrokerControlClient.class);
		
		PeerSpec mockPeer = EasyMock.createMock(PeerSpec.class);
		
		ServiceID peerServiceID = createServiceID(peerSpec, peerPublicKey, PeerConstants.LOCAL_WORKER_PROVIDER);
		
		EasyMock.expect(mockPeer.getServiceID()).andReturn(peerServiceID).anyTimes();
		
		if (oldPeers != null) {
			for (Iterator<LocalWorkerProvider> iterator = oldPeers.iterator(); iterator.hasNext();) {
				EasyMock.reset(iterator.next());
			}
		}	
		
		if (testJobs != null && oldPeers != null) {
			for (TestJob testJob : testJobs) {
				for (LocalWorkerProvider lwp : oldPeers) {
					RequestSpec requestSpec = testJob.getRequestByPeer(application, lwp);
					lwp.finishRequest(requestSpec);
				}
			}
		}
		
		if (oldPeers != null) {
			for (Iterator<LocalWorkerProvider> iterator = oldPeers.iterator(); iterator.hasNext();) {
				EasyMock.replay(iterator.next());
			}
		}	
		
		List<PeerSpec> peers = new ArrayList<PeerSpec>();
		if (peerSpec != null) {
			peers.add(mockPeer);
		}
		
		if (isBrokerStarted) {			
			newLogger.info("Operation succeed.");
			brokerControlClientMock.operationSucceed(ControlOperationResultMatcher.noError());
		} else {
			brokerControlClientMock.operationSucceed(
					ControlOperationResultMatcher.eqCauseType("Broker control was not started", ModuleNotStartedException.class));
			newLogger.error("Broker control was not started.");
		}

		EasyMock.replay(mockPeer);
		EasyMock.replay(newLogger);
		EasyMock.replay(brokerControlClientMock);

		clientID.setPublicKey(brokerOD.getDeploymentID().getPublicKey());
		AcceptanceTestUtil.setExecutionContext(component, brokerOD, clientID);
		
		brokerControl.setPeers(brokerControlClientMock, peers);
		
		if (oldPeers != null) {
			for (LocalWorkerProvider lwp : oldPeers) {
				EasyMock.verify(lwp);
			}
		}
		
		EasyMock.verify(brokerControlClientMock);
		EasyMock.verify(newLogger);
		
		component.setLogger(oldLogger);
	}
	
	public ServiceID createServiceID(PeerSpec peer, String publicKey, String serviceName) {
		String userName = peer.getAttribute(OurGridSpecConstants.ATT_USERNAME);
		String serverName = peer.getAttribute(OurGridSpecConstants.ATT_SERVERNAME);
		
		return new ServiceID(new ContainerID(userName, serverName, PeerConstants.MODULE_NAME, publicKey), serviceName);
	}
	
	public DeploymentID createPeerDeploymentID(String peerPublicKey, PeerSpec peerSpec) {
		String peerName = peerSpec.getAttribute(OurGridSpecConstants.ATT_USERNAME);
		String peerServer = peerSpec.getAttribute(OurGridSpecConstants.ATT_SERVERNAME);
		
		DeploymentID peerDeploymentID = new DeploymentID(new ContainerID(peerName, peerServer, PeerConstants.MODULE_NAME, peerPublicKey), 
				PeerConstants.LOCAL_WORKER_PROVIDER);
		
		return peerDeploymentID;
	}

	public PeerSpec createPeerSpec(String userName, String serverName) {
		Map<String,String> attributes = new HashMap<String, String>();
		attributes.put(OurGridSpecConstants.ATT_USERNAME, userName);
		attributes.put(OurGridSpecConstants.ATT_SERVERNAME, serverName);
		PeerSpec peerSpec = new PeerSpec(attributes);
		return peerSpec;	
	}
	
	public void setPeers(boolean isBrokerStarted, List<PeerSpec> peers, List<String> publicKeys, BrokerServerModule component ) {
		CommuneLogger oldLogger = component.getLogger();
		CommuneLogger newLogger = EasyMock.createMock(CommuneLogger.class);
		
		component.setLogger(newLogger);
		
		newLogger.info("Trying to set peers.");
		
		BrokerControl brokerControl = brokerAcceptanceUtil.getBrokerControl(component);
		ObjectDeployment brokerOD = brokerAcceptanceUtil.getBrokerControlDeployment(component);
		
		BrokerControlClient brokerControlClientMock = EasyMock.createMock(BrokerControlClient.class);
		
		DeploymentID clientID = new DeploymentID(new ServiceID("a", "b", "c", "d"));
		AcceptanceTestUtil.publishTestObject(application, clientID, brokerControlClientMock, BrokerControlClient.class);
		
		List<PeerSpec> mockPeers = new ArrayList<PeerSpec>();
		
		for (int i = 0; i < peers.size(); i++) {
			PeerSpec mockPeerSpec = EasyMock.createMock(PeerSpec.class);
			
			ServiceID peerServiceID = createServiceID(peers.get(i), publicKeys.get(i), PeerConstants.LOCAL_WORKER_PROVIDER);
			EasyMock.expect(mockPeerSpec.getServiceID()).andReturn(peerServiceID).anyTimes();
			
			EasyMock.replay(mockPeerSpec);
			mockPeers.add(mockPeerSpec);
		}
		newLogger.info("Operation succeed.");

		if (isBrokerStarted) {			
			brokerControlClientMock.operationSucceed(ControlOperationResultMatcher.noError());
		} else {
			brokerControlClientMock.operationSucceed(
					ControlOperationResultMatcher.eqCauseType("Broker control was not started", ModuleNotStartedException.class));
			newLogger.error("Broker control was not started.");
		}
		
		
		
		EasyMock.replay(brokerControlClientMock);
		EasyMock.replay(newLogger);

		AcceptanceTestUtil.setExecutionContext(component, brokerOD, brokerOD.getDeploymentID().getPublicKey());
		brokerControl.setPeers(brokerControlClientMock, mockPeers);
		
		for (int i = 0; i < mockPeers.size(); i++) {
			EasyMock.verify(mockPeers.get(i));
		}
		
		EasyMock.verify(brokerControlClientMock);
		EasyMock.verify(newLogger);
		
		component.setLogger(oldLogger);
	}
}
